package com.common.shiro.util;

import java.util.concurrent.atomic.AtomicInteger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.springframework.beans.factory.InitializingBean;

/**
 * 输错5次密码锁定，ehcache.xml配置
 * 
 * @author limk
 * @date 2018年2月12日 下午9:05:25
 * @version 1.0
 */
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher
		implements InitializingBean {
	private final static Logger logger = LogManager
			.getLogger(RetryLimitCredentialsMatcher.class);
	
	private final static String DEFAULT_CHACHE_NAME = "passwordRetryCache";
	private final static int TIMES = 5;
	private final CacheManager cacheManager;
	private String retryLimitCacheName;
	private Cache<String, AtomicInteger> passwordRetryCache;

	public RetryLimitCredentialsMatcher(CacheManager cacheManager) {
		this.cacheManager = cacheManager;
		this.retryLimitCacheName = DEFAULT_CHACHE_NAME;
	}

	@Override
	public boolean doCredentialsMatch(AuthenticationToken authcToken,
			AuthenticationInfo info) {
		String username = (String) authcToken.getPrincipal();
		// retry count + 1
		AtomicInteger retryCount = passwordRetryCache.get(username);
		if (retryCount == null) {
			retryCount = new AtomicInteger(0);
			passwordRetryCache.put(username, retryCount);
		}
		if (retryCount.incrementAndGet() > TIMES) {
			// if retry count > 5 throw
			logger.warn("username: " + username
					+ " tried to login more than 5 times in period");
			throw new ExcessiveAttemptsException();
		}

		boolean matches = super.doCredentialsMatch(authcToken, info);
		if (matches) {
			// clear retry data
			passwordRetryCache.remove(username);
		}
		return matches;
	}

	@Override
    public void setHashAlgorithmName(String hashAlgorithmName) {
        super.setHashAlgorithmName(hashAlgorithmName);
    }

    @Override
    public void setHashIterations(int hashIterations) {
        super.setHashIterations(hashIterations);
    }

    @Override
	public void afterPropertiesSet() throws Exception {
		this.passwordRetryCache = cacheManager.getCache(retryLimitCacheName);
	}
	
	public String getRetryLimitCacheName() {
		return retryLimitCacheName;
	}

	public void setRetryLimitCacheName(String retryLimitCacheName) {
		this.retryLimitCacheName = retryLimitCacheName;
	}
}
